package com.suray.wcs.service.core.path.api.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.path.core.Route;
import com.suray.basic.wcs.path.core.api.impl.DifFloorRouteFactoryImp;
import com.suray.basic.wcs.path.exception.CreatePathFailedException;
import com.suray.wcs.res.enums.RgvStatus;
import com.suray.wcs.service.core.path.api.RgvTaskAssign;
import com.suray.wcs.service.core.util.CommonUtil;
import com.suray.wcs.service.core.util.LockNodeManager;
import com.suray.wcs.service.core.util.SysConfigUtil;
import com.suray.wcs.service.enums.*;
import com.suray.wcs.service.init.SystemInit;
import com.suray.wcs.service.pojo.Rgv;
import com.suray.wcs.service.system.entity.AssignConfigDB;
import com.suray.wcs.service.system.entity.NodeDB;
import com.suray.wcs.service.system.entity.TaskDB;
import com.suray.wcs.service.system.entity.TaskDetailDB;
import com.suray.wcs.service.system.service.IAssignConfigService;
import com.suray.wcs.service.system.service.impl.NodeDBServiceImpl;
import com.suray.wcs.service.system.service.impl.TaskDBServiceImpl;
import com.suray.wcs.service.system.service.impl.TaskDetailServiceImpl;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
@Primary
public class RgvTaskAssignImpl implements RgvTaskAssign {
    private static Logger log = LoggerFactory.getLogger(RgvTaskAssignImpl.class);
    @Autowired
    private TaskDBServiceImpl taskService;
    @Autowired
    private TaskDetailServiceImpl taskDetailService;
    @Autowired
    private NodeDBServiceImpl nodedbService;
    @Autowired
    private IAssignConfigService assignConfigService;

    @Value("${suray.rgvTaskAssign.enableRgvRegionLimit:false}")
    private boolean enableRgvRegionLimit;
    @Value("${suray.rgvTaskAssign.taskCost:10000}")
    private int taskCost;

    /**
     * 将任务与最适Rgv绑定
     * 预分配
     *
     * @param taskDB
     * @return
     */
    @Override
    public Rgv bindAvailableRgvWithTask(TaskDB taskDB) {
        log.info("分配执行中: " + taskDB);
        Rgv availableRgv;
        if (taskDB.getPreProcessingRgvNo() == null) {
            // 未进行预分配的进行预分配，可能存在分不到车
            availableRgv = bindAvailableRgvWithUATask(taskDB, CommonUtil.PRE_ASSIGN_RGV);
        } else {
            // 已经预分配的优化预分配，优化结果可能是改变或者不变
            availableRgv = bindAvailableRgvWithUATask(taskDB, CommonUtil.RE_PRE_ASSIGN_RGV);
        }
        return availableRgv;
    }

    /**
     * 将未预分配任务与最适Rgv绑定
     * 可能存在未找到车辆
     *
     * @param unassignedTask
     * @return
     */
    private Rgv bindAvailableRgvWithUATask(TaskDB unassignedTask, Integer type) {
        // 获取最合适的执行该任务的小车
        Rgv availableRgv = this.getMostAvailableRgv(unassignedTask, type, null);
        if (availableRgv == null) {
            log.warn("任务taskId={}，未分配到小车", unassignedTask.getTaskId());
            TaskDetailDB detailDB = taskDetailService.getTaskDetail(unassignedTask.getTaskId(), DetailProcess.PRE_ASSIGN_FAIL, null, null, null, PrecessStatus.CONDUCT,
                    unassignedTask.getTips(), null);
            taskDetailService.updateTaskDetailCompleteTime(detailDB, PrecessStatus.EXCEPTION);
        }
        if (SysConfigUtil.PRE_ASSIGN_ADJUST) {
            // 更新任务的业务对象和数据库对象
            if (availableRgv != null) {
                if (CommonUtil.PRE_ASSIGN_RGV.equals(type)) {
                    taskService.updateTaskPreProcessingRgvNo(unassignedTask, availableRgv.getRgvDB().getRgvNo(), TaskRgvProgress.PREASSIGN);
                    taskService.updateTaskTipsById(unassignedTask, "");
                }
            }
        } else {
            if (availableRgv != null) {
                taskService.updateTaskProcessingRgvNoAndPreProcessingRgvNoAndStatus(unassignedTask, availableRgv.getRgvDB().getRgvNo(), availableRgv.getRgvDB().getRgvNo(), TaskStatus.WAIT, TaskRgvProgress.ASSIGNED_TO_RGV);
                taskService.updateTaskTipsById(unassignedTask, "");
            }
        }
        return availableRgv;
    }

    /**
     * 获取最优的执行车辆
     * @param unassignedTask
     * @param type
     * @param oldRgv
     * @return
     */
    private Rgv getMostAvailableRgv(TaskDB unassignedTask, Integer type, Rgv oldRgv) {
        Rgv availableRgv;
        // 出入移同一个节点的任务，限制分车数量可配置
        availableRgv = processSameNodeTask(unassignedTask, type, oldRgv);
        if (availableRgv != null) {
            log.info("分配任务{}给出库限制车辆{}", unassignedTask.getTaskId(), availableRgv.getRgvName());
            return availableRgv;
        }
        // 必须分给一个车的，直接分车
        availableRgv = taskAssignRgvBySingleRgvFlag(unassignedTask, type);
        if (availableRgv != null) {
            return availableRgv;
        }
        // 有配置，找出当前层已有任务的车的数量和任务数量，判断是否需要调车，如果不需要，则在当前层车里分车，如果需要调车，则在有空闲的非当前层的车里调车。
        Integer endLayer = unassignedTask.selectEndNode().getZ();
        Integer zoneId = unassignedTask.getZoneId();
        // 同层已分配车辆数量限制，如果该层已分配或预分配的车辆数量已达到限制数量，则在该层已分配的车辆里预分配该任务
        AssignConfigDB assignConfigDB = assignConfigService.getAssignConfigByFloorAndZoneId(endLayer, zoneId);
        if (assignConfigDB != null) {
            Integer rgvLimit = assignConfigDB.getRgvLimit();
            Integer averageDB = assignConfigDB.getAverage();
            Set<Integer> rgvNos = taskService.getRgvNoByFloor(endLayer, zoneId);
            if (rgvNos.size() < rgvLimit) {
                List<Rgv> currentFloorZoneRgvList = SystemInit.getCurrentFloorZoneRgvList(endLayer, zoneId);
                removeZoneLimitRgv(unassignedTask, type, oldRgv, currentFloorZoneRgvList);
                // 如果没有可用小车，则需要调车
                if (CollectionUtils.isEmpty(currentFloorZoneRgvList)) {
                    availableRgv = getRgv(unassignedTask, type, oldRgv, null, endLayer, zoneId, assignConfigDB, averageDB, rgvNos);
                } else {
                    //分配任务给当前层小车（1.当前层的小车，任务数小于平均数或者没有平均数则分给当前层的车，如果都大于等于平均数，则可以跨层调车）
                    if (averageDB == null) {
                        availableRgv = getTheBestRoadAvailableRgv(unassignedTask, currentFloorZoneRgvList);
                    } else {
                        Iterator<Rgv> currentFloorZoneRgvSecIt = currentFloorZoneRgvList.iterator();
                        while (currentFloorZoneRgvSecIt.hasNext()) {
                            Rgv currentFloorZoneRgvSec = currentFloorZoneRgvSecIt.next();
                            List<TaskDB> rgvTaskDBList = taskService.findTaskListByRgvNo(currentFloorZoneRgvSec.getRgvDB().getRgvNo());
                            if ((CommonUtil.RE_PRE_ASSIGN_RGV.equals(type) && checkRgv(currentFloorZoneRgvSec)) || (rgvTaskDBList != null && rgvTaskDBList.size() >= averageDB)) {
                                currentFloorZoneRgvSecIt.remove();
                            }
                        }
                        if (CollectionUtils.isEmpty(currentFloorZoneRgvList)) {
                            availableRgv = getRgv(unassignedTask, type, oldRgv, null, endLayer, zoneId, assignConfigDB, averageDB, rgvNos);
                            return availableRgv;
                        } else {
                            availableRgv = getTheBestRoadAvailableRgv(unassignedTask, currentFloorZoneRgvList);
                        }
                    }
                }
                return availableRgv;
            } else if (rgvNos.size() == rgvLimit) {
                availableRgv = currentFloorAssignedRgvListProcess(type, unassignedTask, rgvNos, oldRgv, averageDB);
                return availableRgv;
            } else {
                String tips = String.format("任务taskId=%s暂不分车，原因：当前层执行任务的小车数量%d[%s]已超过限制数量%s",
                        unassignedTask.getTaskId().toString(),
                        rgvNos.size(),
                        rgvNos.stream().map(Object::toString).collect(Collectors.joining(",")),
                        rgvLimit.toString());
                log.info(tips);
                taskService.updateTaskTipsById(unassignedTask, tips);
                return null;
            }
        } else {
            List<Rgv> rgvList = SystemInit.getCanRunRgvList();
            removeZoneLimitRgv(unassignedTask, type, oldRgv, rgvList);
            availableRgv = getTheBestRoadAvailableRgv(unassignedTask, rgvList);
            return availableRgv;
        }
    }

    private Rgv getRgv(TaskDB unassignedTask, Integer type, Rgv oldRgv, Rgv availableRgv, Integer endLayer, Integer zoneId, AssignConfigDB assignConfigDB, Integer averageDB, Set<Integer> rgvNos) {
        if (zoneId == null || MoveRgvType.CROSS_FLOOR.getValue().equals(assignConfigDB.getMoveRgvType())) {
            // 跨层调车
            availableRgv = crossLayerAssignedRgv(type, unassignedTask, endLayer, rgvNos, averageDB, oldRgv, zoneId);
        } else if (MoveRgvType.CROSS_ZONE.getValue().equals(assignConfigDB.getMoveRgvType())) {
            // 跨区调车
            availableRgv = currentFloorAssignRgv(type, unassignedTask, endLayer, rgvNos, averageDB, oldRgv, zoneId);
        }
        return availableRgv;
    }

    /**
     * 去除区域限制的车辆
     *
     * @param unassignedTask
     * @param type
     * @param oldRgv
     * @param currentFloorZoneRgvList
     */
    private void removeZoneLimitRgv(TaskDB unassignedTask, Integer type, Rgv oldRgv, List<Rgv> currentFloorZoneRgvList) {
        currentFloorZoneRgvList.remove(oldRgv);
        Iterator<Rgv> currentFloorZoneRgvIt = currentFloorZoneRgvList.iterator();
        while (currentFloorZoneRgvIt.hasNext()) {
            Rgv currentFloorZoneRgv = currentFloorZoneRgvIt.next();
            if ((CommonUtil.RE_PRE_ASSIGN_RGV.equals(type) && checkRgv(currentFloorZoneRgv))
                    || !execAreAssigmentTask(currentFloorZoneRgv, unassignedTask)) {
                currentFloorZoneRgvIt.remove();
            }
        }
    }

    private List<Rgv> processPriorityModeRgv(List<Rgv> currentFloorRgvList, TaskType taskType) {
        if (TaskType.IN.equals(taskType)) {
            return processCurrentFloorRgvList(currentFloorRgvList, PriorityMode.IN.getValue());
        } else if (TaskType.OUT.equals(taskType) || TaskType.TRANSFER.equals(taskType)) {
            return processCurrentFloorRgvList(currentFloorRgvList, PriorityMode.OUT.getValue());
        }
        return currentFloorRgvList;
    }

    private List<Rgv> processCurrentFloorRgvList(List<Rgv> currentFloorRgvList, Integer priorityModeValue) {
        // 如果有该模式下的空闲车，则优先分车，如果没有空闲车，如果有非该模式下的空闲车，则非该模式下的空闲车优先分车，如果没有，则该模式下的非空闲车优先分车。
        List<Rgv> currentFloorModeFreeRgvList = Lists.newArrayList();
        List<Rgv> currentFloorModeNoFreeRgvList = Lists.newArrayList();
        List<Rgv> currentFloorNoModeFreeRgvList = Lists.newArrayList();
        Iterator<Rgv> currentFloorModeRgvIt = currentFloorRgvList.iterator();
        while (currentFloorModeRgvIt.hasNext()) {
            Rgv currentFloorModeRgv = currentFloorModeRgvIt.next();
            if (priorityModeValue.equals(currentFloorModeRgv.getRgvDB().getPriorityMode())) {
                if(isReadRgv(currentFloorModeRgv)){
                    currentFloorModeFreeRgvList.add(currentFloorModeRgv);
                }else {
                    currentFloorModeNoFreeRgvList.add(currentFloorModeRgv);
                }
            }
            if (!priorityModeValue.equals(currentFloorModeRgv.getRgvDB().getPriorityMode())
                    && isReadRgv(currentFloorModeRgv)) {
                currentFloorNoModeFreeRgvList.add(currentFloorModeRgv);
                currentFloorModeRgvIt.remove();
            }
        }
        // 该模式下有空闲车
        if (CollectionUtils.isNotEmpty(currentFloorModeFreeRgvList)) {
            return currentFloorModeFreeRgvList;
        }
        if (CollectionUtils.isNotEmpty(currentFloorNoModeFreeRgvList)) {
            return currentFloorNoModeFreeRgvList;
        }
        if (CollectionUtils.isNotEmpty(currentFloorModeNoFreeRgvList)) {
            return currentFloorModeNoFreeRgvList;
        }
        return currentFloorRgvList;
    }

    /**
     * 出入移同一个节点的任务，限制分车数量可配置，分车先从已分配的车辆中分配
     * 如果不存在或小于节点限制数量，则走原分车逻辑
     * @param unassignedTask
     * @param type
     * @param oldRgv
     * @return
     */
    private Rgv processSameNodeTask(TaskDB unassignedTask, Integer type, Rgv oldRgv) {
        NodeDB node = null;
        if (TaskType.OUT.equals(unassignedTask.getTaskType())) {
            Node endNode = unassignedTask.selectEndNode();
            if (endNode != null) {
                node = nodedbService.getNodeDB(endNode);
            }
            if (node != null && node.getLimitRgvCount() != null) {
                return getSameNodeRgv(node.getNodeId(), node.getLimitRgvCount(), unassignedTask, type, oldRgv);
            }
        } else if (TaskType.IN.equals(unassignedTask.getTaskType())) {
            node = nodedbService.getNodeDB(unassignedTask.selectStartNode());
            if (node != null && node.getLimitRgvCount() != null) {
                return getSameNodeRgv(node.getNodeId(), node.getLimitRgvCount(), unassignedTask, type, oldRgv);
            }
        } else if (TaskType.TRANSFER.equals(unassignedTask.getTaskType())) {
            node = nodedbService.getNodeDB(unassignedTask.selectStartNode());
            if (node != null && node.getLimitRgvCount() != null) {
                Rgv rgv = getSameNodeRgv(node.getNodeId(), node.getLimitRgvCount(), unassignedTask, type, oldRgv);
                if (rgv != null) {
                    return rgv;
                } else {
                    node = nodedbService.getNodeDB(unassignedTask.selectEndNode());
                    if (node != null && node.getLimitRgvCount() != null) {
                        rgv = getSameNodeRgv(node.getNodeId(), node.getLimitRgvCount(), unassignedTask, type, oldRgv);
                        return rgv;
                    } else {
                        return null;
                    }
                }
            } else {
                node = nodedbService.getNodeDB(unassignedTask.selectEndNode());
                if (node != null && node.getLimitRgvCount() != null) {
                    Rgv rgv = getSameNodeRgv(node.getNodeId(), node.getLimitRgvCount(), unassignedTask, type, oldRgv);
                    return rgv;
                } else {
                    return null;
                }
            }
        }
        return null;
    }

    /**
     * 限制节点数量分车逻辑，如果是单巷道单车的，需要分给同一个车，
     * 如果节点限制车数量等于0或小于配置数量，则走原逻辑，如果已经
     * 达到数量，则在这些已经分配的车辆中继续分车。
     *
     * @param unassignedTask
     * @param type
     * @param oldRgv
     * @return
     */
    private Rgv getSameNodeRgv(Integer nodeId, Integer maxRgvCount, TaskDB unassignedTask, Integer type, Rgv oldRgv) {
        // 获取限制车辆
        Set<Integer> rgvNos = taskService.queryTaskByLimitRgvFlag(nodeId, type);
        if (rgvNos.size() == 0 || maxRgvCount == 0 || rgvNos.size() < maxRgvCount) {
            return null;
        } else {
            List<Rgv> onlineAndLocationRgvList = SystemInit.getOnlineAndLocationRgvList();
            onlineAndLocationRgvList.remove(oldRgv);
            onlineAndLocationRgvList.removeIf(onlineAndLocationRgv -> (CommonUtil.RE_PRE_ASSIGN_RGV.equals(type) && checkRgv(onlineAndLocationRgv))
                    || !execAreAssigmentTask(onlineAndLocationRgv, unassignedTask)
                    || !rgvNos.contains(onlineAndLocationRgv.getRgvDB().getRgvNo()));
            if (onlineAndLocationRgvList.size() == 0 || onlineAndLocationRgvList.size() < maxRgvCount) {
                return null;
            }
            // 必须分给一个车的，直接分车
            Rgv availableRgv = taskAssignRgvBySingleRgvFlag(unassignedTask, type);
            if (availableRgv != null) {
                log.info("出库口限制分车，分配任务{}给{}，单巷道{}", unassignedTask.getTaskId(), availableRgv.getRgvName(), unassignedTask.getSingleRgvFlag());
                return availableRgv;
            }
            return getTheBestRoadAvailableRgv(unassignedTask, onlineAndLocationRgvList);
        }
    }

    private Rgv currentFloorAssignedRgvListProcess(Integer type, TaskDB unassignedTask, Set<Integer> rgvNos, Rgv oldRgv, Integer averageDB) {
        Rgv availableRgv;
        String tips = String.format("所有可分车量：{%s}。", String.join(",", rgvNos.stream().map(x -> x.toString()).collect(Collectors.toList())));
        List<Rgv> currentFloorAssignedRgvList = SystemInit.getCurrentFloorAssignedRgvList(rgvNos);
        currentFloorAssignedRgvList.remove(oldRgv);
        if (CollectionUtils.isNotEmpty(currentFloorAssignedRgvList)) {
            currentFloorAssignedRgvList.removeIf(currentFloorAssignedRgv -> CommonUtil.RE_PRE_ASSIGN_RGV.equals(type) && checkRgv(currentFloorAssignedRgv));
            tips = tips + String.format("当前区可分车量：{%s}。",
                    String.join(",", currentFloorAssignedRgvList.stream().map(x -> x.getRgvDB().getRgvNo().toString()).collect(Collectors.toList())));
            if (averageDB == null) {
                if (CollectionUtils.isNotEmpty(currentFloorAssignedRgvList)) {
                    availableRgv = getTheBestRoadAvailableRgv(unassignedTask, currentFloorAssignedRgvList, tips);
                    return availableRgv;
                } else {
                    taskService.updateTaskTipsById(unassignedTask, tips);
                    return null;
                }
            } else {
                if (CollectionUtils.isNotEmpty(currentFloorAssignedRgvList)) {
                    List<Rgv> copyCurrentFloorAssignedRgvList = new ArrayList<>(currentFloorAssignedRgvList);
                    removeLimitRgv(averageDB, currentFloorAssignedRgvList);
                    tips = tips + String.format("去除任务数限制当前区可分车量：{%s}。",
                            currentFloorAssignedRgvList.stream().map(x -> x.getRgvDB().getRgvNo().toString()).collect(Collectors.joining(",")));
                    if (CollectionUtils.isNotEmpty(currentFloorAssignedRgvList)) {
                        availableRgv = getTheBestRoadAvailableRgv(unassignedTask, currentFloorAssignedRgvList, tips);
                    } else {
                        // 全部分满了则按最优路径分
                        copyCurrentFloorAssignedRgvList.removeIf(copyCurrentFloorAssignedRgv -> (CommonUtil.RE_PRE_ASSIGN_RGV.equals(type) && checkRgv(copyCurrentFloorAssignedRgv)));
                        tips = tips + String.format("全部分满了按最优路径分, 可分车量：",
                                copyCurrentFloorAssignedRgvList.stream().map(x -> x.getRgvDB().getRgvNo().toString()).collect(Collectors.joining(",")));
                        availableRgv = getTheBestRoadAvailableRgv(unassignedTask, copyCurrentFloorAssignedRgvList, tips);
                    }
                    return availableRgv;
                } else {
                    taskService.updateTaskTipsById(unassignedTask, tips);
                    return null;
                }
            }
        }
        return null;
    }

    /**
     * 跨区调车逻辑，1.获取当前层非当前分区的小车，且已分了当前层当前分区任务的车，如果没有分车限制，则在这些车集合里分车
     * 2.有分车限制，则把已达到任务数量的小车排除掉，然后在这些车集合里分车
     * 3.如果当前层非该区域，有未分任务的车，则在这些车集合里分车
     *
     * @param type
     * @param unassignedTask
     * @param endLayer
     * @param rgvNos
     * @param averageDB
     * @param oldRgv
     * @param zoneId
     */
    private Rgv currentFloorAssignRgv(Integer type, TaskDB unassignedTask, Integer endLayer, Set<Integer> rgvNos, Integer averageDB, Rgv oldRgv, Integer zoneId) {
        Rgv availableRgv;
        String tips = String.format("所有可分车量：{%s}。", String.join(",", rgvNos.stream().map(Object::toString).collect(Collectors.toList())));
        List<Rgv> currentFloorNoZoneAssignedRgvList = SystemInit.getCurrentFloorNoZoneAssignedRgvList(endLayer, rgvNos, zoneId);
        removeZoneLimitRgv(unassignedTask, type, oldRgv, currentFloorNoZoneAssignedRgvList);
        tips = tips + String.format("当前区可分车量：{%s}。",
                currentFloorNoZoneAssignedRgvList.stream().map(x -> x.getRgvDB().getRgvNo().toString()).collect(Collectors.joining(",")));
        if (averageDB == null) {
            if (CollectionUtils.isNotEmpty(currentFloorNoZoneAssignedRgvList)) {
                availableRgv = getTheBestRoadAvailableRgv(unassignedTask, currentFloorNoZoneAssignedRgvList, tips);
                if (availableRgv != null) {
                    return availableRgv;
                }
            }
        } else {
            if (CollectionUtils.isNotEmpty(currentFloorNoZoneAssignedRgvList)) {
                removeLimitRgv(averageDB, currentFloorNoZoneAssignedRgvList);
                tips = tips + String.format("去除任务数限制当前区可分车量：{%s}。",
                        currentFloorNoZoneAssignedRgvList.stream().map(x -> x.getRgvDB().getRgvNo().toString()).collect(Collectors.joining(",")));
                if (CollectionUtils.isNotEmpty(currentFloorNoZoneAssignedRgvList)) {
                    availableRgv = getTheBestRoadAvailableRgv(unassignedTask, currentFloorNoZoneAssignedRgvList, tips);
                    if (availableRgv != null) {
                        return availableRgv;
                    }
                }
            }
        }

        // 当前层非该区域，未分任务的车
        List<Rgv> currentFloorNoZoneNoAssignedRgvList = SystemInit.getCurrentFloorNoZoneNoAssignedRgvList(endLayer, rgvNos, zoneId);
        removeZoneLimitRgv2(type, unassignedTask, oldRgv, currentFloorNoZoneNoAssignedRgvList);

        tips = tips + String.format("当前层非该区域，未分任务的车量：{%s}。",
                currentFloorNoZoneNoAssignedRgvList.stream().map(x -> x.getRgvDB().getRgvNo().toString()).collect(Collectors.joining(",")));
        if (CollectionUtils.isEmpty(currentFloorNoZoneNoAssignedRgvList)) {
            taskService.updateTaskTipsById(unassignedTask, tips);
            return null;
        } else {
            availableRgv = getTheBestRoadAvailableRgv(unassignedTask, currentFloorNoZoneNoAssignedRgvList, tips);
            return availableRgv;
        }
    }

    /**
     * 去除被区域限制的车辆
     * @param type
     * @param unassignedTask
     * @param oldRgv
     * @param currentFloorNoZoneNoAssignedRgvList
     */
    private void removeZoneLimitRgv2(Integer type, TaskDB unassignedTask, Rgv oldRgv, List<Rgv> currentFloorNoZoneNoAssignedRgvList) {
        currentFloorNoZoneNoAssignedRgvList.remove(oldRgv);
        Iterator<Rgv> currentFloorNoZoneNoAssignedRgvIt = currentFloorNoZoneNoAssignedRgvList.iterator();
        while (currentFloorNoZoneNoAssignedRgvIt.hasNext()) {
            Rgv currentFloorNoZoneNoAssignedRgv = currentFloorNoZoneNoAssignedRgvIt.next();
            if ((CommonUtil.RE_PRE_ASSIGN_RGV.equals(type) && checkRgv(currentFloorNoZoneNoAssignedRgv)) || !isReadRgv(currentFloorNoZoneNoAssignedRgv)
                    || !execAreAssigmentTask(currentFloorNoZoneNoAssignedRgv, unassignedTask)) {
                currentFloorNoZoneNoAssignedRgvIt.remove();
            }
        }
    }

    /**
     * 去除任务数限制当前区可分车量
     *
     * @param averageDB
     * @param currentFloorNoZoneAssignedRgvList
     */
    private void removeLimitRgv(Integer averageDB, List<Rgv> currentFloorNoZoneAssignedRgvList) {
        Iterator<Rgv> currentFloorNoZoneRgvForAverageIt = currentFloorNoZoneAssignedRgvList.iterator();
        while (currentFloorNoZoneRgvForAverageIt.hasNext()) {
            Rgv currentFloorNoZoneRgvForAverage = currentFloorNoZoneRgvForAverageIt.next();
            List<TaskDB> rgvTaskDBList = taskService.findTaskListByRgvNo(currentFloorNoZoneRgvForAverage.getRgvDB().getRgvNo());
            if (rgvTaskDBList != null && rgvTaskDBList.size() >= averageDB) {
                currentFloorNoZoneRgvForAverageIt.remove();
            }
        }
    }

    /**
     * 跨层调车逻辑，1.非当前层，且已分了当前层任务的车，如果没有分车限制，则在这些车集合里分车
     * 2.有分车限制，则把已达到任务数量的小车排除掉，然后在这些车集合里分车
     * 3.如果没有非当前层已分任务的小车，则获取当前库区非当前层的所有车进行分车
     *
     * @param type
     * @param unassignedTask
     * @param endLayer
     * @param rgvNos
     * @param averageDB
     * @param oldRgv
     * @param zoneId
     */
    private Rgv crossLayerAssignedRgv(Integer type, TaskDB unassignedTask, int endLayer, Set<Integer> rgvNos, Integer averageDB, Rgv oldRgv, Integer zoneId) {
        Rgv availableRgv = null;
        String tips = String.format("所有可分车量：{%s}。", String.join(",", rgvNos.stream().map(Object::toString).collect(Collectors.toList())));
        // 非当前层，且已分了当前层任务的车
        List<Rgv> noCurrentFloorAssignedRgvList = SystemInit.getNoCurrentFloorAssignedRgvList(endLayer, rgvNos, zoneId);
        noCurrentFloorAssignedRgvList.remove(oldRgv);
        if (CollectionUtils.isNotEmpty(noCurrentFloorAssignedRgvList)) {
            noCurrentFloorAssignedRgvList.removeIf(notCurrentFloorAssignedRgv -> (CommonUtil.RE_PRE_ASSIGN_RGV.equals(type) && checkRgv(notCurrentFloorAssignedRgv))
                    || !execAreAssigmentTask(notCurrentFloorAssignedRgv, unassignedTask));
            tips = tips + String.format("非当前层可分车量：{%s}。",
                    noCurrentFloorAssignedRgvList.stream().map(x -> x.getRgvDB().getRgvNo().toString()).collect(Collectors.joining(",")));
            if (averageDB == null) {
                if (CollectionUtils.isNotEmpty(noCurrentFloorAssignedRgvList)) {
                    availableRgv = getTheBestRoadAvailableRgv(unassignedTask, noCurrentFloorAssignedRgvList, tips);
                    if (availableRgv != null) {
                        return availableRgv;
                    }
                }
            } else {
                if (CollectionUtils.isNotEmpty(noCurrentFloorAssignedRgvList)) {
                    removeLimitRgv(averageDB, noCurrentFloorAssignedRgvList);
                    tips = tips + String.format("去除任务数限制非当前层可分车量：：{%s}。",
                            noCurrentFloorAssignedRgvList.stream().map(x -> x.getRgvDB().getRgvNo().toString()).collect(Collectors.joining(",")));
                    if (CollectionUtils.isNotEmpty(noCurrentFloorAssignedRgvList)) {
                        availableRgv = getTheBestRoadAvailableRgv(unassignedTask, noCurrentFloorAssignedRgvList, tips);
                        if (availableRgv != null) {
                            return availableRgv;
                        }
                    }
                }
            }
        }
        // 非当前层，未分任务的车
        List<Rgv> notCurrentFloorRgvList = SystemInit.getNotCurrentFloorRgvList(endLayer, rgvNos, zoneId);
        removeZoneLimitRgv2(type, unassignedTask, oldRgv, notCurrentFloorRgvList);
        tips = tips + String.format("非当前层所有可分车量：{%s}。",
                noCurrentFloorAssignedRgvList.stream().map(x -> x.getRgvDB().getRgvNo().toString()).collect(Collectors.joining(",")));
        if (CollectionUtils.isEmpty(notCurrentFloorRgvList)) {
            taskService.updateTaskTipsById(unassignedTask, tips);
            return null;
        } else {
            availableRgv = getTheBestRoadAvailableRgv(unassignedTask, notCurrentFloorRgvList, tips);
            return availableRgv;
        }
    }

    /**
     * 当前车状态判断
     * @param rgv
     * @return true 不可用 false 可用
     */
    private boolean checkRgv(Rgv rgv) {
        if (rgv.getRgvStatus() == null
                || rgv.getRgvStatus() == RgvStatus.ERROR || rgv.getElectricStatus() == ElectricStatus.LOW_BATTERY
                || (rgv.getRgvStatus() == RgvStatus.CHARGING && rgv.getBattery() < rgv.getRgvDB().getAssignBatterySize())
                || (rgv.getRgvStatus() == RgvStatus.CHARGING && rgv.getBattery() >= rgv.getRgvDB().getAssignBatterySize()
                && rgv.getBattery() < rgv.getRgvDB().getMaxBatterySize() && SystemInit.isTimeOut(rgv))) {
            return true;
        }
        return false;
    }

    /**
     * 是否有空闲的车，如果有，则重新预分配
     * @param rgv
     * @return true 可用 false 不可用
     */
    private boolean isReadRgv(Rgv rgv) {
        if (rgv.getCurTask() == null && rgv.getCurLocation() != null
                && ((rgv.getRgvStatus() == RgvStatus.CHARGING && rgv.getBattery() >= rgv.getRgvDB().getAssignBatterySize()
                && rgv.getBattery() < rgv.getRgvDB().getMaxBatterySize() && !SystemInit.isTimeOut(rgv))
                || rgv.getRgvStatus() == RgvStatus.READY)
                && !taskService.existUnFinishTask(rgv)) {
            return true;
        }
        return false;
    }

    private Rgv getTheBestRoadAvailableRgv(TaskDB unassignedTask, List<Rgv> rgvList) {
        return getTheBestRoadAvailableRgv(unassignedTask, rgvList, null);
    }

    /**
     * 获取最适合该任务的小车 获取行驶路径最短的可到达的小车
     * 预分配，可能找不到可执行的车辆
     *
     * @param unassignedTask
     * @return
     */
    private Rgv getTheBestRoadAvailableRgv(TaskDB unassignedTask, List<Rgv> rgvList, String tips) {
        Rgv availableRgv = null;
        DifFloorRouteFactoryImp routeFactory;
        if (rgvList.isEmpty()) {
            log.warn("无可运行小车");
            String msg = String.format("任务taskId=%s暂不分车，原因：无可运行小车", unassignedTask.getTaskId().toString());
            tips = tips == null ? msg : tips + msg;
            taskService.updateTaskTipsById(unassignedTask, tips);
            return null;
        }
        rgvList = processPriorityModeRgv(rgvList, unassignedTask.getTaskType());
        Map<String, String> assignRgvReason = new HashMap<>();
        long minPathLength = -1;// 任意较大值
        for (Rgv rgv : rgvList) {
            Node rgvReadyLocation;
            if (rgv.getCurTask() == null || rgv.getCurTask().getTaskId() == null) {
                rgvReadyLocation = rgv.getRgvDB().getLocationNode();
            } else {
                // 该Rgv还有未完成任务,则找最后一个任务的终点
                TaskDB taskDB = taskService.findLastPreAndAssignTaskList(rgv.getRgvDB().getRgvNo());
                if (taskDB != null) {
                    rgvReadyLocation = taskDB.selectEndNode();
                } else {
                    rgvReadyLocation = rgv.getRgvDB().getLocationNode();
                }
            }
            // 任务目标位置: 默认起点, 起点为空则是终点
            Node taskStartNode = unassignedTask.getStartNodeStr() != null ? unassignedTask.selectStartNode() : unassignedTask.selectEndNode();
            List<Route> startPaths;
            long startCost = 0;
            routeFactory = new DifFloorRouteFactoryImp(nodedbService.getNodeList(),
                    LockNodeManager.getLockedNodesExceptSelf(rgv), rgv.generateWCSTimeModuleBO(),
                    rgv.getRgvDB().getRgvType());
            try {
                if (rgvReadyLocation == null) {
                    log.info("{},当前位置为空！", rgv.getRgvName());
                    continue;
                }
                startPaths = routeFactory.createRoute(rgvReadyLocation, taskStartNode, false);
            } catch (CreatePathFailedException e) {
                log.info("任务taskId={},路径规划失败！{}", unassignedTask.getTaskId(), e.getMessage());
                assignRgvReason.put(rgv.getRgvDB().getRgvNo().toString(), "路径规划失败");
                continue;
            }
            for (Route route : startPaths) {
                if (Long.MAX_VALUE - route.getCost() < startCost) {
                    startCost = Long.MAX_VALUE;
                } else {
                    startCost += route.getCost();
                }
            }
            int availableRgvTaskCount = taskService.countByProcessingRgvNo(rgv.getRgvDB().getRgvNo());
            if (Long.MAX_VALUE - availableRgvTaskCount * taskCost < startCost) {
                startCost = Long.MAX_VALUE;
            } else {
                startCost += availableRgvTaskCount * taskCost;
            }
            if (minPathLength == -1) {
                minPathLength = startCost;
            }
            if (startCost <= minPathLength) {
                minPathLength = startCost;
                availableRgv = rgv;
            }
        }
        if (availableRgv == null) {
            String msg = String.format("任务taskId=%s暂不分车，原因：%s",
                    unassignedTask.getTaskId().toString(), JSON.toJSONString(assignRgvReason));
            tips = tips == null ? msg : tips + msg;
            taskService.updateTaskTipsById(unassignedTask, tips);
        }
        return availableRgv;
    }

    @Override
    public boolean preBindAvailableRgvWithTask(TaskDB taskDB) {
        return bindAvailableRgvWithUATask(taskDB, CommonUtil.PRE_ASSIGN_RGV) == null ? false : true;
    }

    @Override
    public Rgv bindNewAvailableRgvWithTask(TaskDB taskDB) {
        Rgv oldRgv = null;
        if (taskDB.selectProcessingRgvPojo() != null || taskDB.getPreProcessingRgvNo() != null) {
            oldRgv = taskDB.selectProcessingRgvPojo() != null ? taskDB.selectProcessingRgvPojo() : SystemInit.getByRgvNoTask(taskDB.getPreProcessingRgvNo());
        }
        Rgv availableRgv = getMostAvailableRgv(taskDB, CommonUtil.RE_PRE_ASSIGN_RGV, oldRgv);
        // 更新任务的业务对象和数据库对象
        if (SysConfigUtil.PRE_ASSIGN_ADJUST) {
            // 更新任务的业务对象和数据库对象
            if (availableRgv != null) {
                taskService.updateTaskPreProcessingRgvNoAndProcessingRgvNo(taskDB, availableRgv.getRgvDB().getRgvNo(), null, TaskRgvProgress.PREASSIGN);
            }
        } else {
            if (availableRgv != null) {
                taskService.updateTaskProcessingRgvNoAndStatus(taskDB, availableRgv.getRgvDB().getRgvNo(), TaskStatus.WAIT, TaskRgvProgress.ASSIGNED_TO_RGV);
            }
        }
        return availableRgv;
    }


    /**
     * 根据执行区域配置验证改车是否可以分配该任务
     *
     * @return
     */
    private boolean execAreAssigmentTask(Rgv rgv, TaskDB taskDB) {
        // 任务目标位置: 默认起点, 起点为空则是终点
        Node taskStartNode = taskDB.getStartNodeStr() != null ? taskDB.selectStartNode() : taskDB.selectEndNode();
        //当该车层与起始层不一致，并该车不可跨层则忽略
        if (rgv.getCurLocation().getZ() != taskStartNode.getZ() && !rgv.getRgvDB().getIsPassFloor()) {
            return false;
        }
        // 判断区域限制
        if (enableRgvRegionLimit) {
            if (rgv.getRgvDB().getXRegion() == null || rgv.getRgvDB().getYRegion() == null || rgv.getRgvDB().getZRegion() == null) {
                return false;
            }
            String[] rgvXRegion = rgv.getRgvDB().getXRegion().split("-");
            String[] rgvYRegion = rgv.getRgvDB().getYRegion().split("-");
            String[] rgvZRegion = rgv.getRgvDB().getZRegion().split("-");
            //入库任务，终点区域限制
            if (TaskType.IN.equals(taskDB.getTaskType())) {
                if (!Arrays.asList(rgvXRegion).contains(taskDB.selectEndNode().getX() + "") ||
                        !Arrays.asList(rgvYRegion).contains(taskDB.selectEndNode().getY() + "") ||
                        !Arrays.asList(rgvZRegion).contains(taskDB.selectEndNode().getZ() + "")) {
                    return false;
                }
            } else {
                if (!Arrays.asList(rgvXRegion).contains(taskStartNode.getX() + "") ||
                        !Arrays.asList(rgvYRegion).contains(taskStartNode.getY() + "") ||
                        !Arrays.asList(rgvZRegion).contains(taskStartNode.getZ() + "")) {
                    return false;
                }
            }
        }
        return true;
    }


    /**
     * 单巷道分车，如果该巷道已经有任务且已分车则直接分车，如果没有则走之前的分车逻辑
     *
     * @return
     */
    private Rgv taskAssignRgvBySingleRgvFlag(TaskDB unassignedTask, Integer type) {
        if (StringUtils.isBlank(unassignedTask.getSingleRgvFlag())) {
            return null;
        }
        // 移库任务需要特殊处理，起点巷道判断如果没有，还需要判断终点巷道是否有
        List<TaskDB> taskDBList = taskService.findTasksBySingleRgvFlag(unassignedTask.getSingleRgvFlag(), CommonUtil.PROCESSING_RGV_NO_NOT_NULL);
        if (CommonUtil.PRE_ASSIGN_RGV.equals(type)) {
            if (CollectionUtils.isNotEmpty(taskDBList)) {
                Rgv rgv = SystemInit.getByRgvNo(taskDBList.get(0).getProcessingRgvNo());
                log.info("同组有未完成的任务{}，分配该任务给小车{}", taskDBList.get(0).getTaskId(), taskDBList.get(0).getProcessingRgvNo());
                return rgv;
            } else {
                // 移库任务,单巷道单车
                if (StringUtils.isNotBlank(unassignedTask.getGroupIdSecond())) {
                    taskDBList = taskService.findTasksBySingleRgvFlag(unassignedTask.getGroupIdSecond(), CommonUtil.PROCESSING_RGV_NO_NOT_NULL);
                    if (CollectionUtils.isNotEmpty(taskDBList)) {
                        Rgv rgv = SystemInit.getByRgvNo(taskDBList.get(0).getPreProcessingRgvNo());
                        log.info("同组有未完成的任务{}，分配该任务给小车{}", taskDBList.get(0), rgv.getRgvDB().getRgvNo());
                        return rgv;
                    } else {
                        taskDBList = taskService.findTasksBySingleRgvFlag(unassignedTask.getSingleRgvFlag(), CommonUtil.PRE_PROCESSING_RGV_NO_NOT_NULL_PROCESSING_RGV_NO_NULL);
                        if (CollectionUtils.isNotEmpty(taskDBList)) {
                            Rgv rgv = SystemInit.getByRgvNo(taskDBList.get(0).getPreProcessingRgvNo());
                            log.info("同组有未完成的任务{}，分配该任务给小车{}", taskDBList.get(0), rgv.getRgvDB().getRgvNo());
                            return rgv;
                        } else {
                            taskDBList = taskService.findTasksBySingleRgvFlag(unassignedTask.getGroupIdSecond(), CommonUtil.PRE_PROCESSING_RGV_NO_NOT_NULL_PROCESSING_RGV_NO_NULL);
                            if (CollectionUtils.isNotEmpty(taskDBList)) {
                                Rgv rgv = SystemInit.getByRgvNo(taskDBList.get(0).getPreProcessingRgvNo());
                                log.info("同组有未完成的任务{}，分配该任务给小车{}", taskDBList.get(0), rgv.getRgvDB().getRgvNo());
                                return rgv;
                            }
                        }
                    }
                } else {
                    taskDBList = taskService.findTasksBySingleRgvFlag(unassignedTask.getSingleRgvFlag(), CommonUtil.PRE_PROCESSING_RGV_NO_NOT_NULL_PROCESSING_RGV_NO_NULL);
                    if (CollectionUtils.isNotEmpty(taskDBList)) {
                        Rgv rgv = SystemInit.getByRgvNo(taskDBList.get(0).getPreProcessingRgvNo());
                        log.info("同组有未完成的任务{}，分配该任务给小车{}", taskDBList.get(0), rgv.getRgvDB().getRgvNo());
                        return rgv;
                    }
                }
            }
        } else if (CommonUtil.RE_PRE_ASSIGN_RGV.equals(type)) {
            if (CollectionUtils.isNotEmpty(taskDBList)) {
                Rgv rgv = SystemInit.getByRgvNo(taskDBList.get(0).getProcessingRgvNo());
                log.info("同组有未完成的任务{}，分配该任务给小车{}", taskDBList.get(0), rgv.getRgvDB().getRgvNo());
                return rgv;
            } else {
                // 移库任务,单巷道单车
                if (StringUtils.isNotBlank(unassignedTask.getGroupIdSecond())) {
                    taskDBList = taskService.findTasksBySingleRgvFlag(unassignedTask.getGroupIdSecond(), CommonUtil.PROCESSING_RGV_NO_NOT_NULL);
                    if (CollectionUtils.isNotEmpty(taskDBList)) {
                        Rgv rgv = SystemInit.getByRgvNo(taskDBList.get(0).getPreProcessingRgvNo());
                        log.info("同组有未完成的任务{}，分配该任务给小车{}", taskDBList.get(0), rgv.getRgvDB().getRgvNo());
                        return rgv;
                    }
                }
            }
        }
        return null;
    }
}
